package com.jackstraw.jack_base.remote_command.service.impl;

import com.jackstraw.jack_base.remote_command.entity.Conn;
import com.jackstraw.jack_base.remote_command.service.JschService;
import com.jackstraw.jack_base.util.FileUtil;
import com.jackstraw.jack_base.util.StringUtil;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.ChannelShell;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.output.ByteArrayOutputStream;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;


@Slf4j
public abstract class AbstractJschServiceImpl implements JschService {

    @Override
    public void upload(Conn conn, String directory, String uploadFile) throws Exception {
        this.upload(conn, directory, new File(uploadFile));
    }

    @Override
    public void upload(Conn conn, String directory, File file) throws Exception {
        Map<String, List<File>> fileMap = FileUtil.fileAll(file, directory);
        for (String newDirectory : fileMap.keySet()) {
            fileMap.get(newDirectory).stream().forEach(newFile -> {
                try {
                    upload(conn, newDirectory, new FileInputStream(newFile), newFile.getName());
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
        }
    }

    @Override
    public void notUnixUpload(Conn conn, String directory, InputStream inputStream, String uploadFileName) throws Exception {
        try {
            if (!this.checkFileExists(conn, directory)) {
                this.mkdir(conn, directory);
            }
            if ("~".equals(directory)) {
                String home = conn.getSftp().home();
                conn.getChannelSftp().cd(home);
            } else {
                conn.getChannelSftp().cd(directory);
            }
            conn.getChannelSftp().put(inputStream, uploadFileName);
        } finally {
            FileUtil.IoUtilByHutool.close(inputStream);
        }
    }

    @Override
    public void upload(Conn conn, String directory, InputStream inputStream, String uploadFileName) throws Exception {
        this.notUnixUpload(conn, directory, inputStream, uploadFileName);
        this.unix(conn, directory.concat("/").concat(uploadFileName));
    }

    @Override
    public void mkdir(Conn conn, String directory) throws Exception {
        directory = directory.replace("\\\\", "/");
        if (!this.checkFileExists(conn, directory)) {
            List<String> pathSplit = new ArrayList<>(Arrays.asList(directory.split("/")));
            String newPath = "";
            for (String path : pathSplit) {
                if (StringUtil.StringUtilsBylang3.isEmpty(path)) {
                    continue;
                }
                newPath = newPath.concat("/").concat(path);
                if (!this.checkFileExists(conn, newPath)) {
                    conn.getSftp().mkdir(newPath);
                }
            }
        }
    }

    @Override
    public Boolean checkFileExists(Conn conn, String directory) throws Exception {
        if ("~".equals(directory)) {
            String home = conn.getSftp().home();
            return conn.getSftp().exist(home);
        }
        return conn.getSftp().exist(directory);
    }

    @Override
    public void uploadReplace(Conn conn, String directory, InputStream inputStream, String fileName, Map<String, String> dictPropertiesMap) throws Exception {
        inputStream = this.replaceInputStream(inputStream, dictPropertiesMap);
        upload(conn, directory, inputStream, fileName);
    }

    @Override
    public String execShell(Conn conn, String cmd) throws Exception {
        String response = "";
        ByteArrayOutputStream responseStream = new ByteArrayOutputStream();
        ChannelExec channelExec = conn.getChannelExec();
        channelExec.setOutputStream(responseStream);
        channelExec.setCommand(cmd);
        channelExec.connect();
        while (channelExec.isConnected()) {
            TimeUnit.MILLISECONDS.sleep(50);
        }
        response = new String(responseStream.toByteArray());
        if (response.endsWith("\n")) {
            response = response.substring(0, response.length() - "\n".length());
        }
        return response;
    }

    @Override
    public List<String> execShell(Conn conn, List<String> cmdList) throws Exception {
        List<String> responseList = new ArrayList<>();
        for (String cmd : cmdList) {
            responseList.add(execShell(conn, cmd));
        }
        return responseList;
    }

    @Override
    public String execAllShell(Conn conn, List<String> cmdList, Charset charset) throws Exception {
        InputStream inputStream = null;
        try {
            StringBuffer response = new StringBuffer();
            //打开shell
            ChannelShell channelShell = conn.getChannelShell();
            PrintStream printStream = new PrintStream(channelShell.getOutputStream(), true);
            //连接
            channelShell.connect();
            //输入命令
            cmdList.stream().forEach(cmd -> {
                printStream.println(cmd);
            });
            // 输入离开命令
            printStream.println("exit");
            printStream.close();
            //获取输入流
            inputStream = channelShell.getInputStream();
            //转换为String
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            String line = "";
            while ((line = bufferedReader.readLine()) != null) {
                log.info("输出结果为：{}", line);
                response.append(line);
            }
            return response.toString();
        } finally {
            FileUtil.IoUtilByHutool.close(inputStream);
        }
    }
}
